package com.ht.interfaces.service;

import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.sql.DataSource;

import com.ht.api.db.Db;
import com.ht.api.db.DbConfig;
import com.ht.api.db.DbList;
import com.ht.api.db.Entity;
import com.ht.api.db.StreamLoadConfig;
import com.ht.api.db.constant.CacheConstants;
import com.ht.api.db.task.HtTaskExecutor;
import com.ht.api.db.util.MqUtil;
import com.ht.api.db.util.RedisUtil;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ht.interfaces.utils.AESEncrypter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LinkService {

    /**
     * 获取短链关联内容
     */
    public static JSONObject getContent (String host, JSONObject link, String openid) {
        DataSource ds = TenantService.getDs(host);

        String relationId = link.getStr("relation_id");
        String relationTable = link.getStr("relation_type");

        JSONObject result = JSONUtil.createObj();
        result.set("openid", openid);

        // 获取内容，并填充到结果
        Entity relation = Db.createSqlParser(relationTable).findById(ds, relationId);
        switch (relationTable) {
            case "writings":
                result.set("title", relation.get("title"));
                result.set("content", relation.get("content"));

                // 文章需要判断是否展示广告
                if (relation.get("ad_status") != null && relation.getInt("ad_status") == 1) {
                    JSONArray ads = findAdToUser(host, ds, openid);
                    result.set("ad", ads);
                }

                break;

            case "questionnaire":
                result.set("questionnaire_id", relationId);
                result.set("name", relation.get("name"));
                result.set("content", relation.get("content"));
                break;
        }

        log.info("result " + result.toStringPretty());

        return result;
    }

    /**
     * 通过openid寻找符合用户的广告
     */
    public static JSONArray findAdToUser (String host, DataSource ds, String openid) {
        JSONArray ads = JSONUtil.createArray();

        // 查找广告任务
        String sql = """
                select * from ad_user_task 
                    where openid = ? and (status = 1 or (status = 3 and DATE_FORMAT(act_time, '%Y-%m-%d') <= DATE_FORMAT(CURDATE(), '%Y-%m-%d') )) and ad_position = ? and plan_day <= DATE_FORMAT(CURDATE(), '%Y-%m-%d') 
                    and sys_deleted = 1 
                    order by plan_day asc, slot_time asc, sys_time asc limit ? 
                """;

        List<Entity> adList = new CopyOnWriteArrayList<>();

        List<Runnable> runList = new ArrayList<>();
        // 顶部广告
        runList.add(()->{
            DbList list = Db.query(ds, sql, openid, "web_top", 1);
            adList.addAll(list);
        });

        // 底部广告
        runList.add(()->{
            DbList list = Db.query(ds, sql, openid, "web_bottom", 20);
            adList.addAll(list);
        });
        HtTaskExecutor.execute(runList);

        String time = DateUtil.now();

        // 格式化广告内容
        List<Runnable> taskRunList = new ArrayList<>();
        for (Entity task : adList) {
            task.setTable("ad_user_task");
            task.set("status", 3);
            if (StrUtil.isBlank(task.getStr("act_time"))) {
                task.set("act_time", time);
            }
            taskRunList.add(()->{
                JSONObject ad = buildAd(host, ds, task);
                ads.add(ad);
            });
        }
        HtTaskExecutor.execute(taskRunList);

        // 这里向mq发送保存adList的请求
        MqUtil.send(TenantService.getTenantId(host), adList);

//        Db.insertBatchWithStream(TenantService.getSLConfig(host), adList);

        return ads;
    }

    /**
     * 格式化广告内容
     */
    public static JSONObject buildAd (String host, DataSource ds, Entity task) {
        JSONObject ad = JSONUtil.createObj();
        ad.set("task_id", task.getMainId());
        ad.set("content", task.getStr("creative_content"));
        ad.set("position", task.getStr("ad_position"));

        String adPosition = task.getStr("ad_position");

        int adType = task.getInt("ad_type");

        if (adPosition.equals("web_bottom")) {

            JSONObject material = task.getJSONObject("creative_material");
            if (adType == 5) {//商品推荐
                ad.set("ad_type", "goods");
                ad.set("url", material.get("url"));
                ad.set("img", material.get("img"));
                ad.set("title", material.get("title"));
                ad.set("relation_id", material.get("relation_id"));
            } else if (adType == 4 ) { //课程资料
                ad.set("ad_type", "lesson");
                ad.set("url", host + "/call/ReceiveLesson?task_id="+task.getMainId()+"&lesson_id=" + material.getStr("relation_id"));
                ad.set("relation_id", material.get("relation_id"));
            } else if (adType == 6) { //调查问卷
                ad.set("ad_type", "questionnaire");

                String linkId = material.getStr("link_id");
                Entity shortLinkState = Entity.create("short_link_state");
                shortLinkState.set("link_id", linkId);
                shortLinkState.set("state", getRandomCode(ds));
                shortLinkState.set("context", task.get("context"));
                shortLinkState.set("appid", task.get("appid"));

                Db.insert(ds, shortLinkState);
                ad.set("url", host + "/l/" + shortLinkState.getStr("state"));

                ad.set("relation_id", material.get("relation_id"));
            } else if (adType == 7) { //直播预约
                ad.set("ad_type", "live");
                ad.set("title", material.get("title"));
                ad.set("time", material.get("time"));
                ad.set("url", host + "/call/ReservationLive?task_id="+task.getMainId()+"&live_id=" + material.getStr("relation_id"));
                ad.set("relation_id", material.get("relation_id"));
            } else if (adType == 8	) { //邀请进群
                ad.set("ad_type", "groupchat");
                ad.set("title", material.get("title"));
                ad.set("reward", material.get("reward"));

                String url = Db.createSqlParser("wx_chat_way").select("qr_code").where("position_id", material.getStr("position")).val(ds);
                ad.set("url", url);

                ad.set("relation_id", material.get("relation_id"));
            }
        } else if (adPosition.equals("web_top")) {
            if (adType == 9) {
                ad.set("ad_type", "script");
            }
        }

        return ad;
    }

    /**
     * 组装授权url
     */
    public static String doAuthorizeUrl (String host, JSONObject link)  {
        String appid = link.getStr("appid");
        String state = link.getStr("state");

        String redirectUri = null;
        try {
            redirectUri = URLEncoder.encode(host + "/l/" + state, "utf-8");
        } catch (Exception e) {
        }

        Entity app = RedisUtil.get(CacheConstants.KEY_APP + appid);

        String cropid= null;
        JSONArray tokenParam = app.getJSONObject("config").getJSONArray("token_param");
        for (int i = 0; i < tokenParam.size(); i++) {
            JSONObject obj = tokenParam.getJSONObject(i);
            if (obj.getStr("name").equals("corpid")) {
                cropid = obj.getStr("value");
                break;
            }
        }

        String agentid= app.getStr("agentid");

        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&agentid=%s#wechat_redirect";

        return String.format(url, cropid, redirectUri, agentid);
    }

    /**
     * 获取链接关联信息
     */
    public static Entity getLink (String host, String state) {
        DataSource ds = TenantService.getDs(host);
        String sql = """
                SELECT
                	s.appid,
                	s.state,
                	l.relation_id,
                	l.relation_type,
                	s.context
                FROM
                	short_link_state s
                	LEFT JOIN short_link l ON s.link_id = l.main_id
                WHERE
                	s.state = ?
                """;

        Entity link = Db.findOne(ds, sql, state);

        if (link.getStr("relation_type").equals("ad_questionnaire")) {
            link.set("relation_type", "questionnaire");
        }

        return link;
    }

    /**
     * 解析用户OPENID
     */
    public static String analysisOpenid (String appId, String code) {

        // 获取平台ID
        Entity entity = RedisUtil.get(CacheConstants.KEY_APP + appId);
        String platformId = entity.getStr("pid");

        // 获取token
        String tokenKey = String.format("token:%s:%s", platformId, appId);
        String token = RedisUtil.get(tokenKey);

        // 获取访问用户身份
        String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=%s&code=%s";
        HttpRequest request = HttpUtil.createGet(String.format(url, token, code));
        HttpResponse response = request.execute();
        String result = response.body();

        if (response.isOk()) {
            log.info("[ApiUtil]第三方接口返回：{}", result);
        } else {
            log.error("[ApiUtil]第三方接口请求失败: {} - {}", response.getStatus(), result);
            return "-1";
        }
        JSONObject codeResult = JSONUtil.parseObj(result);
        String openid = codeResult.getStr("external_userid");
        if (StrUtil.isBlank(openid)) {
            openid = codeResult.getStr("openid");
            if (StrUtil.isBlank(openid)) {
                openid = codeResult.getStr("userid");
            }
        }

        return openid;
    }

    public static JSONObject buildClientInfo (HttpServletRequest request) {
        JSONObject clientInfo = JSONUtil.createObj();
        // 1. 获取IP地址
        clientInfo.put("ip", getClientIp(request));

        // 2. 解析User-Agent
        String userAgentString = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgentUtil.parse(userAgentString);
        clientInfo.put("browser", userAgent.getBrowser().getName());
        clientInfo.put("browserVersion", userAgent.getVersion());
        clientInfo.put("os", userAgent.getOs().getName());
        clientInfo.put("platform", userAgent.getPlatform().getName());
        clientInfo.put("isMobile", userAgent.isMobile());
        clientInfo.putAll(extractDeviceInfo(userAgentString));

        return clientInfo;
    }

    /**
     * 获取IP
     * @param request
     * @return
     */
    private static String getClientIp(HttpServletRequest request) {
        String[] headers = {"X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP"};

        for (String header : headers) {
            String ip = request.getHeader(header);
            if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
                // 处理多个IP的情况（如X-Forwarded-For: client, proxy1, proxy2）
                return ip.split(",")[0].trim();
            }
        }

        return request.getRemoteAddr();
    }

    // 在原有方法中添加设备信息提取
    private static Map<String, String> extractDeviceInfo(String userAgentString) {
        Map<String, String> deviceInfo = new HashMap<>();

        if (userAgentString.contains("Android")) {
            deviceInfo.put("deviceType", "Android");
            // 尝试提取Android设备型号
            String[] parts = userAgentString.split(";");
            for (String part : parts) {
                if (part.trim().matches(".*[A-Z]{2}-[A-Z0-9]+.*")) {
                    deviceInfo.put("deviceModel", part.trim());
                    break;
                }
            }
        }
        else if (userAgentString.contains("iPhone")) {
            deviceInfo.put("deviceType", "iPhone");
            // 提取iPhone型号
            if (userAgentString.matches(".*iPhone\\d+,\\d+.*")) {
                deviceInfo.put("deviceModel",
                        userAgentString.replaceAll(".*(iPhone\\d+,\\d+).*", "$1"));
            }
        }

        return deviceInfo;
    }

    /**
     * 生成一个随机code，并确保此code在short_link表中不存在
     * @param ds 数据源
     * @return
     */
    private static String getRandomCode(DataSource ds) {
        String code = RandomUtil.randomString(7);

        // 查询数据库，如果存在，则递归操作
        boolean exists = Db.createSqlParser("short_link").where("code", code).hasRow(ds);
        if (exists) {
            return getRandomCode(ds);
        }

        return code;
    }

    /**
     * 保存点击日志
     */
    public static void saveClickLog (String host, String openid, JSONObject client, JSONObject link) {
        DataSource ds = TenantService.getDs(host);

        List<Entity> datalist = new ArrayList<>();

        Entity linkClickLogs = Entity.create("short_link_click_logs");
        linkClickLogs.set("openid", openid);
        linkClickLogs.set("appid", link.get("appid"));
        linkClickLogs.set("relation_id", link.get("relation_id"));
        linkClickLogs.set("relation_type", link.get("relation_type"));
        linkClickLogs.set("state", link.get("state"));
        linkClickLogs.set("click_time", DateUtil.now());
        linkClickLogs.set("user_agent", client.toString());
        linkClickLogs.set("status", 0);
        datalist.add(linkClickLogs);

        Entity event = Entity.create("user_event_log");
        event.set("openid", openid);

        if (link.get("relation_type").equals("writings")) {
            event.set("event_type", "link_writings");
        }

        event.set("event_key", "click");
        event.set("relation_id", link.get("relation_id"));
        event.set("relation_type", link.get("relation_type"));
        event.set("event_time", DateUtil.now());
        event.set("event_msg", "");
        event.set("context", link.get("context"));
        datalist.add(event);


        String oneid = Db.createSqlParser("user_origin").where("openid", openid).val(ds, String.class);
        if (StrUtil.isNotBlank(oneid)) {
            Entity device = Entity.create("device_info");
            device.set("main_id", oneid);
            device.set("oneid", oneid);
            device.set("device_type", client.getStr("deviceType"));
            device.set("operating_system", client.getStr("iPhone"));
            device.set("browser_type", client.getStr("browser"));
            datalist.add(device);
        }

        MqUtil.send(TenantService.getTenantId(host), datalist);
    }

}
